#pragma once
#include <unordered_map>
#include <unordered_set>
#include <string>
#include <list>
#include <set>
#include "rapidjson/meta.h"
#include "head.h"

namespace KRPC {

struct FuncConf
{
	std::string 			name;			//接口函数名
	bool 					open = false;	//此接口是否开放给非本地ip访问
	std::set<std::string> 	specify;		//此接口开放条件下指定哪些ip可以访问
	bool 					binded = false;

	METAS(name, open, specify);
	MSGPACK_DEFINE(name, open, specify);
};

class Access
{
public:
	Access(const std::list<FuncConf> &lf, const std::set<std::string> publish) : topics(publish)
	{
		for (auto &fc : lf) {
			if (fc.open) {
				std::unordered_set<uint32_t> supportIp;
				for (auto &ip : fc.specify) {
					supportIp.insert(inet_addr(ip.c_str()));
				}
				conf[fc.name] = std::move(supportIp);
			}
		}
	}

	bool operator()(MsgHead *head, uint32_t ip)
	{
		if (ip != 0x100007f && head->ver != 1) {	//对于外部连接ver必须为1,即必须进行校验
			head->mode = RPC_NO_ACCESS;
			return false;
		}
		switch (head->mode) {
			case RPC_REQ: {
				if (ip == 0x100007f)		//0x100007f为127.0.0.1的网络字节序
					return true;	//对于127.0.0.1的ip默认支持访问
				//printf("ip is %s, name is %s\n", inet_ntoa({ip}), head->name);
				auto it = conf.find(head->name);
				if (it != conf.end()) {//如果找到函数名对应的ip支持列表,并且此列表为空或者列表中包含此ip则返回true,当列表为空表示支持所有ip访问
					if (it->second.empty() || it->second.find(ip) != it->second.end()) {
						return true;
					} else {
						head->mode = RPC_NO_ACCESS;
						return false;
					}
				} else {
					head->mode = RPC_NOT_FOUND;
					return false;
				}
			}
			case RPC_SUB: {
				if (topics.find(head->name) != topics.end()) {
					return true;
				} else {
					head->mode = RPC_NOT_FOUND;
					return false;
				}
			}
			case RPC_HEARTBEAT: {	//心跳信息默认有权限
				return true;
			}
			default: {
				head->mode = RPC_NO_ACCESS;
				return false;
			}
		}
	}

	void update(const FuncConf &fc)
	{
		if (fc.open) {
			std::unordered_set<uint32_t> supportIp;
			for (auto &ip : fc.specify) {
				supportIp.insert(inet_addr(ip.c_str()));
			}
			conf[fc.name] = std::move(supportIp);
		} else {
			conf.erase(fc.name);
		}
	}
	
private:
	//map的key为函数名,value为所支持访问ip的网络字节序列表
	std::unordered_map<std::string, std::unordered_set<uint32_t>> conf;
	std::set<std::string> topics;
};

}
